package net.net23.sysdent.server.jdo.control;

import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;

import net.net23.sysdent.server.jdo.control.search.model.SearchJanitor;
import net.net23.sysdent.server.jdo.control.search.model.SearchJanitorUtils;
import net.net23.sysdent.server.jdo.pojos.Link;
import net.net23.sysdent.server.jdo.pojos.User;
import net.net23.sysdent.shared.validators.StringValidator;

import com.google.appengine.api.datastore.DatastoreNeedIndexException;
import com.google.appengine.api.datastore.DatastoreTimeoutException;

public class LinkController {

	private static final Logger log = Logger.getLogger(LinkController.class
			.getName());

	@SuppressWarnings("unchecked")
	public static Link getLinkByUserAndLink(Long user, String link) {
		PersistenceManager persistenceManager = PMF.get()
				.getPersistenceManager();
		Query query = persistenceManager.newQuery(Link.class);
		query.setFilter("user == userParam && link == linkParam");
		query.declareParameters("Long userParam, String linkParam");
		try {
			List<Link> list = (List<Link>) query.execute(user, link);
			if (list.isEmpty()) {
				return null;
			}
			return list.get(0);
		} finally {
			persistenceManager.close();
		}
	}

	public static Link forceByUserAndLink(Long user, String link) {
		Link _link = getLinkByUserAndLink(user, link);
		if (_link == null) {
			_link = LinkController.save(link, user);
		}
		return _link;
	}

	public static Link save(String link, Long user) {
		Link _link = new Link(link, user);
		_link.rebuildIndexes();
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try {
			pm.makePersistent(_link);
		} finally {
			pm.close();
		}
		return _link;
	}

	@SuppressWarnings("unchecked")
	public static List<Link> getLinks(int offset, int length) {
		PersistenceManager persistenceManager = PMF.get()
				.getPersistenceManager();
		Query query = persistenceManager.newQuery(Link.class);
		query.setRange(offset, length);
		query.setOrdering("creationDate");
		return (List<Link>) query.execute();
	}

	public static List<Link> getLinksByUser(String filters, Long id,
			int offset, int length) {
		if (StringValidator.isEmpty(filters)) {
			return getAllLinksByUser(id, offset, length);
		}
		return getLinksByCriteria(id, filters, 0, 0);
	}

	@SuppressWarnings("unchecked")
	private static List<Link> getAllLinksByUser(Long id, int offset, int length) {
		PersistenceManager persistenceManager = PMF.get()
				.getPersistenceManager();
		Query query = persistenceManager.newQuery(Link.class);
		query.setFilter("user == userParam");
		query.declareParameters("Long userParam");
		if (length > 0) {
			query.setRange(offset, length);
		}
		query.setOrdering("creationDate");
		return (List<Link>) query.execute(id);
	}

	@SuppressWarnings("unchecked")
	public static List<Link> getLinksByCriteria(Long id, String queryString,
			long min, long max) {
		PersistenceManager persistenceManager = PMF.get()
				.getPersistenceManager();
		StringBuffer queryBuffer = new StringBuffer();
		StringBuffer declareParametersBuffer = new StringBuffer();
		queryBuffer.append("SELECT FROM " + Link.class.getName() + " WHERE ");
		Set<String> queryTokens = SearchJanitorUtils
				.getTokensForIndexingOrQuery(queryString,
						SearchJanitor.MAXIMUM_NUMBER_OF_WORDS_TO_SEARCH);
		queryBuffer.append("user == userParam");
		declareParametersBuffer.append("Long userParam");
		List<Object> parametersForSearch = new LinkedList<Object>();
		parametersForSearch.add(id);
		parametersForSearch.addAll(queryTokens);
		int parameterCounter = 0;
		while (parameterCounter < queryTokens.size()) {
			queryBuffer.append(" && ");
			declareParametersBuffer.append(", ");
			queryBuffer.append("keyWords == param" + parameterCounter);
			declareParametersBuffer.append("String param" + parameterCounter);
			parameterCounter++;
		}
		Query query = persistenceManager.newQuery(queryBuffer.toString());
		query.declareParameters(declareParametersBuffer.toString());
		if (min + max > 0) {
			query.setRange(min, max);
		}
		List<Link> result = null;
		try {
			result = (List<Link>) query.executeWithArray(parametersForSearch
					.toArray());

		} catch (DatastoreTimeoutException e) {
			log.severe(e.getMessage());
			log.severe("datastore timeout at: " + queryString);
		} catch (DatastoreNeedIndexException e) {
			log.severe(e.getMessage());
			log.severe("datastore need index exception at: " + queryString);
		}
		return result;
	}

	public static void forceByUser(User user,
			net.net23.sysdent.shared.jto.Link link) {
		Link _link = new Link();
		_link.setCreationDate(new Date());
		_link.setLink(link.getLink());
		_link.setName(link.getName().trim().length() == 0 ? link.getLink()
				: link.getName());
		_link.setUser(user.getId());
		_link.rebuildIndexes();
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try {
			pm.makePersistent(_link);
		} finally {
			pm.close();
		}
	}

	public static void update(net.net23.sysdent.shared.jto.Link link) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try {
			Link dbLink = pm.getObjectById(Link.class, link.getId());
			dbLink.setName(link.getName().trim().length() == 0 ? link.getLink()
					: link.getName());
			dbLink.setLink(link.getLink());
			dbLink.rebuildIndexes();
		} finally {
			pm.close();
		}
	}
}
